home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
020a
/
dvpt20.zip
/
VRMOD.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-12-12
|
15KB
|
723 lines
page 58,132
;****************************************************************
;* *
;* Digitized Voice Programmer's Toolkit *
;* ------------------------------------ *
;* *
;* Sound Recording Primitives *
;* *
;* Copyright (c) 1991, Farpoint Software *
;* *
;****************************************************************
.8086
.MODEL LARGE
;**********************************************************************
;* *
;* Equates *
;* *
;**********************************************************************
tccount equ 72 ;reload count to produce 16572 Hz
countmax_18hz equ 910 ;ratio of new timer rate to standard rate
tcaddrc equ 43h ;timer/counter control register address
tcaddrd0 equ 40h ;timer/counter data register zero (sys clock)
tcmode0a equ 34h ;two-byte mode for system clock timer
tcmode0b equ 24h ;high-byte mode for system clock timer
tclatchcmd0 equ 00h ;latch command for reading timer 0
ppiaddr equ 61h ;programmable peripheral interface address
kbdonly_mask equ 0FDh ;mask config to allow only keyboard interrupt
intmaskaddr equ 21h ;address of the interrupt mask register
kbdint_number equ 9 ;vector number of the keyboard hardware int
;CPU speed calibration initialization parameters
init_delayctr equ 1024
init_cal_increment equ 512
init_cal_passes equ 10
;**********************************************************************
;* *
;* Global variables *
;* *
;**********************************************************************
.DATA
comaddr dw 2ECh
;CPU speed calibration data
delayctr dw init_delayctr
cal_increment dw init_cal_increment
cal_passes dw init_cal_passes
;keyboard hardware interrupt occurrence flag
keyflag db 0
;interrupt controller mask save byte
original_mask db 0
comlist dw 3FCh ;needed addresses of all COM ports
dw 2FCh
dw 3ECh
dw 2ECh
;**********************************************************************
;* *
;* Code *
;* *
;**********************************************************************
.CODE
assume ds:DGROUP
;code-segment storage for keyboard interrupt chain vector
original_kbdint_vec dd 0
;**********************************************************************
;* Keyboard Hardware Interrupt Intercept Routine *
;**********************************************************************
;This routine sets the "keyflag" variable to 1 whenever a keyboard
; interrupt occurs.
kbdint proc far
push ds
push ax
mov ax,DGROUP
mov ds,ax
mov keyflag,1
pop ax
pop ds
jmp dword ptr cs:original_kbdint_vec
kbdint endp
;**********************************************************************
;* Obtain available memory figure from DOS *
;**********************************************************************
;This routine returns a dword indicating the number of bytes of memory
; available for allocation from DOS.
public GETMEMAVAIL
GETMEMAVAIL proc far
push bp
mov bp,sp
mov bx,0FFFFh
mov ah,48h
int 21h
sub bx,16
jc gma_none
sub dx,dx
mov ax,bx
mov cx,4
gma_dshift:
shl ax,1
rcl dx,1
loop gma_dshift
gma_exit:
pop bp
ret
gma_none:
sub ax,ax
sub dx,dx
jmp gma_exit
GETMEMAVAIL endp
;**********************************************************************
;* Calibrated software delay routine *
;**********************************************************************
;lots of nops
rdelay proc near
db init_delayctr dup (90h)
ret ;starting delay value
db (init_delayctr-1) dup (90h)
ret ;should never actually be executed
rdelay endp
;**********************************************************************
;* Set Calibration Constant *
;* *
;* This call simply sets the calibration constant to the *
;* value specified in the parameter. *
;**********************************************************************
;Accepts the following parameters with PASCAL parameter-passing convention:
;Position Size Description
;-------- ---- -----------
; 1 2 The calibration constant to be set.
;There is no return value.
rsc_parm1 equ [bp+6] ;length = 2
rsc_parmlength equ 2
public RSETCAL
RSETCAL proc far
push bp
mov bp,sp
;in case this routine has been called before, erase the "ret" instruction
; that was placed in the delay routine
lea bx,rdelay
add bx,delayctr
mov byte ptr cs:[bx],90h ;this is a "nop" instruction
;get the new delay parameter
mov ax,rsc_parm1
mov delayctr,ax
;insert a "ret" instruction at the new location in the delay routine
lea bx,rdelay
add bx,delayctr
mov byte ptr cs:[bx],0C3h ;this is a "ret" instruction
pop bp
ret rsc_parmlength
RSETCAL endp
;**********************************************************************
;* Calibration procedure *
;* *
;* This routine must be called once before any calls are made *
;* to the recording routine. It measures the CPU execution *
;* speed and saves compensation values. *
;**********************************************************************
;There are no entry parameters.
;The return value is a double word, defined as follows:
;Return value low word Meaning
;--------------------- -------
; 0 success
; 1 this CPU is too slow to accomplish
; normal-speed playback
; 2 operation not possible under Windows
; in "Enhanced" mode
;The return value high word is the actual speed calibration constant
; for this computer
cal_temp1 equ [bp-2] ;length = 2
cal_temp2 equ [bp-4] ;length = 2
cal_locallength equ 4
public RCALIBRATE
RCALIBRATE proc far
push bp
mov bp,sp
sub sp,cal_locallength
push si
;test for the "Enhanced Mode Windows" environment
mov ax,1600h
int 2Fh
cmp al,00h
je cal_no_enh_win
cmp al,80h
je cal_no_enh_win
mov delayctr,1
mov ax,2
jmp cal_exit
cal_no_enh_win:
;in case this routine has been called before, erase the "ret" instruction
; that was placed in the delay routine
lea bx,rdelay
add bx,delayctr
mov byte ptr cs:[bx],90h ;this is a "nop" instruction
;initialize parameters
mov delayctr,init_delayctr
mov cal_increment,init_cal_increment
mov cal_passes,init_cal_passes
;insert a "ret" instruction into the starting location in the delay routine
lea bx,rdelay
add bx,delayctr
mov byte ptr cs:[bx],0C3h ;this is a "ret" instruction
;no interrupts until we are through calibrating
cli
;write the standard setup to timer zero
mov al,tcmode0a
out tcaddrc,al
jmp short $+2
jmp short $+2
mov al,0
out tcaddrd0,al
jmp short $+2
jmp short $+2
out tcaddrd0,al
jmp short $+2
jmp short $+2
;set timer zero to high-byte mode
mov al,tcmode0b
out tcaddrc,al
jmp short $+2
jmp short $+2
mov al,0
out tcaddrd0,al
jmp short $+2
jmp short $+2
;use a "dummy" port address
mov dx,comaddr
;initialize loop count
cal_zerocnt:
sub cx,cx
mov word ptr cal_temp1,0
mov word ptr cal_temp2,0
mov keyflag,0
;synchronize to timer tick
mov ah,0
mov al,tclatchcmd0
out tcaddrc,al
jmp short $+2
jmp short $+2
in al,tcaddrd0
jmp short $+2
jmp short $+2
mov si,ax
cal_sync:
mov al,tclatchcmd0
out tcaddrc,al
jmp short $+2
jmp short $+2
in al,tcaddrd0
jmp short $+2
cmp ax,si
mov si,ax
jbe cal_sync
;calibration loop
cal_dummyloop:
mov al,01h
out dx,al
jmp short $+2
jmp short $+2
add dx,2
in al,dx
shr al,1
shr al,1
shr al,1
shr al,1
mov ah,al
sub dx,2
mov al,00h
out dx,al
jmp short $+2
jmp short $+2
add dx,2
in al,dx
and al,0F0h
or ah,al
mov al,02h
sub dx,2
out dx,al
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
mov al,00h
out dx,al
inc cx
jnz cal_countbytes
cal_countbytes:
inc word ptr cal_temp2
jnz cal_dummydelay
inc word ptr cal_temp1
cal_dummydelay:
call rdelay
inc dx
in al,dx
dec dx
test al,00h ;dummy test for end of recording
jnz cal_checktime
cmp keyflag,0
jne cal_checktime
cal_checktime:
mov al,tclatchcmd0
out tcaddrc,al
jmp short $+2
jmp short $+2
in al,tcaddrd0
sub ah,ah
cmp ax,si
mov si,ax
jbe cal_dummyloop
;kill the old "ret" instruction in the delay routine
lea bx,rdelay
add bx,delayctr
mov byte ptr cs:[bx],90h ;this is a "nop" instruction
;adjust delay counter
mov ax,cal_increment
shr cal_increment,1
cmp cx,countmax_18hz
je cal_setret
jb cal_makefaster
add delayctr,ax
jmp cal_setret
cal_makefaster:
sub delayctr,ax
cal_setret: ;here we insert a new return
lea bx,rdelay
add bx,delayctr
mov byte ptr cs:[bx],0C3h ;this is a "ret" instruction
dec cal_passes
cmp cal_passes,0
je cal_restore
jmp cal_zerocnt
;repair loss of system timer ticks and restore interrupts
cal_restore:
mov bx,40h
mov es,bx
mov bx,6Ch
add word ptr es:[bx],init_cal_passes+1
adc word ptr es:[bx+2],0
cmp word ptr es:[bx+2],18h
jb cal_tc_end
ja cal_tc_midnite
cmp word ptr es:[bx],0B0h
jb cal_tc_end
cal_tc_midnite:
mov byte ptr es:[bx+4],1
sub word ptr es:[bx],0B0h
sbb word ptr es:[bx+2],18h
cal_tc_end:
sti
;determine if CPU is too slow
cal_checkcpu:
cmp delayctr,1
je cal_cpuslow
sub ax,ax
jmp cal_exit
cal_cpuslow:
mov ax,1
cal_exit:
mov dx,delayctr
pop si
add sp,cal_locallength
pop bp
ret
RCALIBRATE endp
;**********************************************************************
;* Record procedure *
;**********************************************************************
;Accepts the following parameters with PASCAL parameter-passing convention:
;Position Size Description
;-------- ---- -----------
; 1 4 A far pointer to the memory block used for voice data.
; 2 4 A dword indicating the length of the memory block.
; 3 2 A word containing the number of the COM port to be used
; for input (1 thru 4).
;The return value is a dword indicating the number of bytes recorded.
;A return value of -1L indicates that the COM port was invalid.
;A full buffer or a break interrupt from the UART stops the recording.
rv_parm1 equ [bp+12] ;length = 4
rv_parm2hi equ [bp+10] ;length = 2
rv_parm2lo equ [bp+8] ;length = 2
rv_parm3 equ [bp+6] ;length = 2
rv_parmlength equ 10
rv_temp1 equ [bp-2] ;length = 2
rv_temp2 equ [bp-4] ;length = 2
rv_locallength equ 4
public RECORDVOICE
RECORDVOICE proc far
push bp
mov bp,sp
sub sp,rv_locallength
push si
;set up com port
mov dx,rv_parm3
cmp dx,1
jae rv_comhirange
jmp rv_badcom
rv_comhirange:
cmp dx,4
jbe rv_lookupcomaddress
jmp rv_badcom
rv_lookupcomaddress:
dec dx
shl dx,1
lea bx,comlist
add bx,dx
mov dx,[bx]
mov comaddr,dx
sub dx,4
in al,dx
jmp short $+2
jmp short $+2
in al,dx
jmp short $+2
jmp short $+2
in al,dx
jmp short $+2
jmp short $+2
add dx,2
in al,dx
jmp short $+2
jmp short $+2
add dx,3
in al,dx
jmp short $+2
jmp short $+2
inc dx
in al,dx
sub dx,2
;mask all interrupts except the keyboard
cli
in al,intmaskaddr
mov original_mask,al
mov al,kbdonly_mask
out intmaskaddr,al
;install the keyboard interrupt intercept routine
sub ax,ax
mov es,ax
mov bx,kbdint_number*4
mov ax,es:[bx]
mov word ptr cs:original_kbdint_vec,ax
mov ax,es:[bx+2]
mov word ptr cs:original_kbdint_vec+2,ax
lea ax,kbdint
mov es:[bx],ax
mov ax,cs
mov es:[bx+2],ax
sti
;set up initial conditions
mov word ptr rv_temp1,0
mov word ptr rv_temp2,0
mov keyflag,0
les bx,dword ptr rv_parm1
mov cx,rv_parm2lo
mov si,rv_parm2hi
cmp cx,0
je rv_recordloop
inc si
;recording loop
rv_recordloop:
mov al,01h
out dx,al
jmp short $+2
jmp short $+2
add dx,2
in al,dx
shr al,1
shr al,1
shr al,1
shr al,1
mov ah,al
sub dx,2
mov al,00h
out dx,al
jmp short $+2
jmp short $+2
add dx,2
in al,dx
and al,0F0h
or ah,al
mov al,02h
sub dx,2
out dx,al
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
mov al,00h
out dx,al
mov es:[bx],ah
inc bx
jnz rv_countbytes
mov ax,es
add ax,1000h
mov es,ax
rv_countbytes:
inc word ptr rv_temp2
jnz rv_delay
inc word ptr rv_temp1
rv_delay:
call rdelay
inc dx
in al,dx
dec dx
test al,10h ;test for end of recording
jnz rv_stop
cmp keyflag,0
jne rv_stop
mov al,tclatchcmd0
out tcaddrc,al
jmp short $+2
jmp short $+2
in al,tcaddrd0
sub ah,ah
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
loop rv_recordloop
dec si
jnz rv_recordloop
rv_stop:
;remove the keyboard interrupt intercept routine
cli
sub ax,ax
mov es,ax
mov bx,kbdint_number*4
mov ax,word ptr cs:original_kbdint_vec
mov es:[bx],ax
mov ax,word ptr cs:original_kbdint_vec+2
mov es:[bx+2],ax
;restore the original interrupt mask
mov al,original_mask
out intmaskaddr,al
sti
;compensate for lost timer ticks
mov dx,rv_parm2hi
mov ax,rv_parm2lo
mov cx,countmax_18hz
div cx
mov bx,40h
mov es,bx
mov bx,6Ch
cli
add es:[bx],ax
adc word ptr es:[bx+2],0
cmp word ptr es:[bx+2],18h
jb rv_tc_end
ja rv_tc_midnite
cmp word ptr es:[bx],0B0h
jb rv_tc_end
rv_tc_midnite:
mov byte ptr es:[bx+4],1
sub word ptr es:[bx],0B0h
sbb word ptr es:[bx+2],18h
rv_tc_end:
sti
;set return value
mov dx,rv_temp1
mov ax,rv_temp2
;exit
rv_exit:
pop si
add sp,rv_locallength
pop bp
ret rv_parmlength
;set return value for COM port out of range
rv_badcom:
mov dx,0FFFFh
mov ax,0FFFFh
jmp rv_exit
RECORDVOICE endp
end